package ppa.application.main;

import java.awt.HeadlessException;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.WindowEvent;
import java.awt.event.WindowListener;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;

import javax.swing.JOptionPane;
import javax.xml.parsers.ParserConfigurationException;

import org.xml.sax.SAXException;

import ppa.application.dom.XMLParser;
import ppa.application.model.Step;
import ppa.application.view.GameWindow;

public class Game implements Serializable {

	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;

	transient private XMLParser parser;
	private List<Step> listSteps;
	private String game;

	private GameWindow gm;

	private Step next = null;
	private Step firstStep = null;
	private boolean first = true;
	private List<String> list;

	private boolean notSaved = false;

	public Game() throws ParserConfigurationException, SAXException,
			IOException {
		parser = new XMLParser();
		listSteps = new ArrayList<Step>();

		gm = new GameWindow();

		list = parser.getGames();
		game = "";

		gm.setVisible(true);

		gm.addTexttoTextArea("Choose a game :");

		for (int i = 0; i < list.size(); i++) {
			gm.addTexttoTextArea((1 + i) + " - " + list.get(i));
		}
		gm.getBtValid().addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent arg0) {
				run();
			}
		});

		gm.getBtSave().addActionListener(new ActionListener() {

			@Override
			public void actionPerformed(ActionEvent arg0) {
				saveGame();
			}
		});
		gm.getBtLoad().addActionListener(new ActionListener() {

			@Override
			public void actionPerformed(ActionEvent arg0) {
				loadGame();
			}
		});
		gm.getBtReInit().addActionListener(new ActionListener() {

			@Override
			public void actionPerformed(ActionEvent arg0) {
				try {
					reInitGame();
				} catch (ParserConfigurationException e) {
					e.printStackTrace();
				} catch (SAXException e) {
					e.printStackTrace();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		});
		gm.getBtCreate().addActionListener(new ActionListener() {

			@Override
			public void actionPerformed(ActionEvent arg0) {
				try {
					createGame();
				} catch (ParserConfigurationException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				} catch (SAXException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				} catch (IOException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
		});

		gm.getTfInput().addKeyListener(new KeyListener() {

			@Override
			public void keyTyped(KeyEvent arg0) {

			}

			@Override
			public void keyReleased(KeyEvent arg0) {

			}

			@Override
			public void keyPressed(KeyEvent arg0) {
				if (arg0.getKeyCode() == 10) {
					run();
				}
			}
		});

		gm.addWindowListener(new WindowListener() {
			public void windowClosed(WindowEvent arg0) {

			}

			public void windowActivated(WindowEvent arg0) {

			}

			public void windowClosing(WindowEvent arg0) {
				// System.out.println("Debug: @closing asking save");
				promptSave();
				// System.out.println("Debug: @closing asked  save");
			}

			public void windowDeactivated(WindowEvent arg0) {

			}

			public void windowDeiconified(WindowEvent arg0) {

			}

			public void windowIconified(WindowEvent arg0) {

			}

			public void windowOpened(WindowEvent arg0) {

			}
		});
	}

	public void reInitGame() throws ParserConfigurationException, SAXException, IOException {
		if (promptSave()) {
			parser = new XMLParser();
			listSteps = new ArrayList<Step>();
			
			list = parser.getGames();
			game = "";
			firstStep = null;
			first = true;
			
			gm.getTaGame().setText("");
			
			gm.addTexttoTextArea("Choose a game :");

			for (int i = 0; i < list.size(); i++) {
				gm.addTexttoTextArea((1 + i) + " - " + list.get(i));
			}

		} else {
			return;
		}
	
	
	}

	public void play() {
		// List<String> list = parser.getGames();
		//
		// System.out.println("Choose a game :");
		//
		// for (int i = 0; i < list.size(); i++) {
		// System.out.println((1 + i) + " - " + list.get(i));
		// }
		//
		// int j;
		// do {
		// j = getKeyboardValue();
		// } while (j > list.size());
		// System.out.println("You chose : " + list.get(j - 1).toString());
		//
		// Step first = parser.startGame(list.get(j - 1));
		// Step next;
		//
		// listSteps.add(first);
		//
		// System.out.println(first.getExposition());
		//
		// j = getKeyboardValue();
		//
		// next = parser.nodeToStep(parser.getNodebySituationCode(j));
		// listSteps.add(next);
		//
		// do {
		// Step temp;
		//
		// System.out.println(next.getExposition());
		// System.out.println(next.getQuestion().getLabel());
		// System.out.println(next.getQuestion().getChoice());
		//
		// j = getKeyboardValue();
		//
		// temp = parser.nodeToStep(parser.getNodebySituationCode(next
		// .getNext().getCode().get(j-1)));
		//
		// next = temp;
		// listSteps.add(next);
		//
		// } while (!next.getExposition().equals("Fin"));
		//
		// System.out.println("Congratulations !!");
	}

	public void run() {
		notSaved = true;
		if (gm.getTfInput().getText() != null
				&& !gm.getTfInput().getText().equals("")) {

			for (int i = 0; i < gm.getTfInput().getText().length(); i++) {
				if (!Character.isDigit(gm.getTfInput().getText().charAt(i))) {
					gm.addTexttoTextArea("Enter a valid number");
					gm.getTfInput().setText("");
					return;
				}
			}

			if (firstStep == null) {
				gm.addTexttoTextArea("You chose : "
						+ list.get(getTextBoxValue() - 1).toString());

				parser.startGame(list.get(getTextBoxValue() - 1));
				firstStep = parser.nodeToStep(parser.getNodebySituationCode(1));
				game = list.get(getTextBoxValue() - 1);

				listSteps.add(firstStep);
				gm.addTexttoTextArea(firstStep.getExposition());
				gm.addTexttoTextArea(firstStep.getQuestion().getLabel());
				int i = 1;
				for (String string : firstStep.getQuestion().getChoice()) {
					gm.addTexttoTextArea(i + ". " + string);
					i++;
				}

				gm.getTfInput().setText("");
			} else {

				if (first) {
					next = parser.nodeToStep(parser
							.getNodebySituationCode(firstStep.getNext()
									.getCode().get(getTextBoxValue() - 1)));
					first = false;
				} else {
					next = parser.nodeToStep(parser.getNodebySituationCode(next
							.getNext().getCode().get(getTextBoxValue() - 1)));
					listSteps.add(next);
				}

				gm.addTexttoTextArea(next.getExposition());
				if (!next.getExposition().equals("Fin")) {
					gm.addTexttoTextArea(next.getQuestion().getLabel());
					int i = 1;
					for (String string : next.getQuestion().getChoice()) {
						gm.addTexttoTextArea(i + ". " + string);
						i++;
					}
					gm.getTfInput().setText("");

				} else {
					gm.addTexttoTextArea("Jeu terminé !");
					gm.addTexttoTextArea("Choisissez un nouveau jeu :");
					listSteps = new ArrayList<Step>();
					list = parser.getGames();
					first = true;
					firstStep = null;
					for (int i = 0; i < list.size(); i++) {
						gm.addTexttoTextArea((1 + i) + " - " + list.get(i));
					}
				}

			}
		}
	}

	public int getTextBoxValue() {
		return Integer.parseInt(gm.getTfInput().getText());
	}

	// public int getKeyboardValue() {
	// int j;
	// Scanner sc = new Scanner(System.in);
	// j = sc.nextInt();
	// return j;
	// }

	public void saveGame() {
		try {

			boolean exists = false;
			String name = "";

			do {
				name = JOptionPane.showInputDialog("Choose a name", "game");
				File directory = new File("saves/");
				File[] list = directory.listFiles();

				for (File file : list) {
					if (name == file.getName()) {
						exists = true;
						gm.addTexttoTextArea("This name already exists");
					}
				}
			} while (exists);

			if (name != null && !name.equals("")) {
				gm.addTexttoTextArea("Saving...");

				FileOutputStream fos = new FileOutputStream("saves/" + name
						+ ".save");
				ObjectOutputStream oos = new ObjectOutputStream(fos);
				oos.writeObject(this);
				oos.flush();
				gm.addTexttoTextArea("Save done");
				notSaved = false;
				oos.close();
				fos.close();

			}

		} catch (IOException e) {
			notSaved = true;
			gm.addTexttoTextArea("Input/Output Exception");
		}
	}

	public void loadGame() {

		gm.getTaGame().setText("");
		gm.addTexttoTextArea("Loading previous saved game");

		File directory = new File("saves/");
		File[] list = directory.listFiles();
		String[] listStr = new String[20];
		int i = 0;

		if (list.length > 0) {
			for (File file : list) {
				if (file.getName().endsWith(".save")) {
					listStr[i] = file.getName();
					i++;
				}
			}
		}

		try {

			String name = (String) JOptionPane.showInputDialog(null,
					"Choose one saved game", "Input",
					JOptionPane.INFORMATION_MESSAGE, null, listStr, listStr[0]);
			if (name != null && !name.equals("")) {

				FileInputStream fis = new FileInputStream("saves/" + name);
				ObjectInputStream ois = new ObjectInputStream(fis);

				Game newGame = (Game) ois.readObject();

				ois.close();
				fis.close();

				parser = new XMLParser();
				notSaved = false;

				firstStep = newGame.firstStep;
				next = newGame.next;
				game = newGame.game;
				first = newGame.first;
				listSteps = newGame.listSteps;

				parser.startGame(game);

				gm.addTexttoTextArea("Load done");
				
				gm.addTexttoTextArea(listSteps.get(listSteps.size() -1).getExposition());
				gm.addTexttoTextArea(listSteps.get(listSteps.size() -1).getQuestion().getLabel());
				int index = 1;
				for (String string : listSteps.get(listSteps.size() -1).getQuestion().getChoice()) {
					gm.addTexttoTextArea(index + ". " + string);
					index++;
				}
			}
		} catch (HeadlessException e) {
			gm.addTexttoTextArea("HeadLess Exception");
		} catch (FileNotFoundException e) {
			gm.addTexttoTextArea("FileNotFound Exception");
		} catch (IOException e) {
			gm.addTexttoTextArea("Input/Output Exception");
		} catch (ClassNotFoundException e) {
			gm.addTexttoTextArea("ClassNotFound Exception");
		} catch (ParserConfigurationException e) {
			gm.addTexttoTextArea("ParserConfiguration Exception");
		} catch (SAXException e) {
			gm.addTexttoTextArea("SAX Exception");
		}
	}

	public void createGame() throws ParserConfigurationException, SAXException, IOException {
		
		if (promptSave()) {
			
		
		 list = parser.getGames();
		 String[] gamel = new String[list.size()];
		 for (int i = 0; i < list.size(); i++) {
				gamel[i] =  list.get(i);
			}
		 parser.startGame((String)JOptionPane.showInputDialog(null, "Edition",
			        "Select a game", JOptionPane.QUESTION_MESSAGE, null,
			        gamel,
			        0));

		

		 String[] listChoice = {"Update exposition","Update Question",
				 "Add awnser", "Update awnser" ,"Remove awnser",
				 "New step","Remove Step","Save","Leave"};
		 String choix="";
		 Step mystep = new Step();
		 int i;
		 
		 do{
			 try{
				 	choix = (String) JOptionPane.showInputDialog(null, "Edition",
			        "Select an action", JOptionPane.QUESTION_MESSAGE, null,
			        listChoice,
			        listChoice[0]);
			 }catch (Exception e) {
				 System.out.println("execption with choix= "+choix);
				 choix = listChoice[9];
			}
		 System.out.println("choix: "+choix);
		 if(choix==listChoice[0]){ // expo
			 i = askSituationCode();
			 mystep = parser.nodeToStep(parser.getNodebySituationCode(i));
			 mystep.setExposition(askString("Change exposition:", mystep.getExposition()));
			 //parser.replaceNodeBySituationCode(i, parser.stepToNode(mystep) );
				
			 
		 }else{
			 if(choix==listChoice[1]){ // q label
				 i = askSituationCode();
				 mystep = parser.nodeToStep(parser.getNodebySituationCode(i));
				 mystep.getQuestion().setLabel(askString("Change question:",
						 mystep.getQuestion().getLabel()));
				// parser.replaceNodeBySituationCode(i, mystep.spteToNode() );
					
				 
			 }else{
				 if(choix==listChoice[2]){ // aws
					 //parser.replaceNodeBySituationCode(2,
						//	 parser.stepToNode(parser.nodeToStep(parser.getNodebySituationCode(2))));
				 }else{
					 if(choix==listChoice[3]){
						 
					 }else{
						 if(choix==listChoice[4]){
							 
						 }else{
							 if(choix==listChoice[5]){//new step
								 
							 }else{
								 if(choix==listChoice[6]){//remove node
									 parser.removeNodeBySituationCode(askSituationCode());
									 
								 }else{
									 if(choix==listChoice[7]){ //save in file.xml
										
									 /*}else{
										 if(choix==listChoice[8]){
											 
										 }else{
											 
										 }*/
									 }
								 }
							 }
						 }
					 } 
				 }
			 }
			 
		 }
		 
		 
		 }while(choix!="Leave"&&choix!=null);
		// }while(choix!=listChoice[8]&&choix!=null);
		 reInitGame();
		 /* list = parser.getGames();

			gm.setVisible(true);

			gm.addTexttoTextArea("Choose a game :");

			for ( i = 0; i < list.size(); i++) {
				gm.addTexttoTextArea((1 + i) + " - " + list.get(i));
			}
			first = true;*/
		}
	}
	
	public String askString(String title, String oldValue){
		String ret;
		try{
			ret = (String)JOptionPane.showInputDialog(title, oldValue);
			ret = ret.replace("\"", "'");
			ret = ret.replace("<", "");
			ret = ret.replace(">", "");
			ret = ret.replace("?", "");
		}catch (Exception e) {
			ret = "";
		}
		return ret;
	}

	public int askSituationCode(){
		return Integer.parseInt((String) JOptionPane.showInputDialog(null,
	            "Choose a situation :",
	            "Select a situation", JOptionPane.QUESTION_MESSAGE,
	            null, parser.getCodes(), "0"));
	}
	
	

	 
	 /** check if save is needed then ask for a save before continues.
	 * 
	 * @optional Use the return to check if user prefer cancel (false) and you
	 * want allow it.
	 * 
	 * @return false if user ask for cancel
	 * 
	 * @return true if save was not needed or if user make or skipped save.
	 * 
	 * 
	 */
	public boolean promptSave() {
		if (notSaved) {
			int wantSave = JOptionPane
					.showConfirmDialog(null,
							"Would you like to save your progress before it gets lost ?");
			if (wantSave == 0) {
				saveGame();
			}
			if (wantSave == 2) {
				return false;
			}
		}
		return true;
	}

}
